﻿namespace SsisLdapSource.DirectoryServicesProtocolsExtensions
{
    using System;
    using System.Collections.Generic;
    using System.DirectoryServices.Protocols;

    public class RangeRetrievalSearchRequest : System.DirectoryServices.Protocols.SearchRequest
    {
        private readonly string rangeExpansionDirectiveTemplate;
        private readonly string initialExpansionDirective;

        public RangeRetrievalSearchRequest(
            string dn,
            string attribute)
        {
            if(string.IsNullOrEmpty(dn))
            {
               throw new ArgumentNullException("dn", "Base DN can't be null in RangeRetrievalSearchRequest"); 
            }

            if (string.IsNullOrEmpty(attribute))
            {
               throw new ArgumentNullException("attribute", "Attribute to expand can't be null in RangeRetrievalSearchRequest");   
            }

            rangeExpansionDirectiveTemplate = string.Format("{0};range={{0}}-{{1}}", attribute);
            initialExpansionDirective = string.Format(rangeExpansionDirectiveTemplate, 0, "*");
            var queryFilter = string.Format("({0}=*)", attribute);
            
            DistinguishedName = dn;
            Filter = queryFilter;
            Scope = SearchScope.Base;
            Attributes.AddRange(new[] { initialExpansionDirective });
        }

        public IEnumerable<string> Execute(LdapConnection ldapConnection)
        {
            var rangeStart = 0;
            var isLastSearch = false;
            var attributeValues = new List<string>();
            var currentExpansionDirective = initialExpansionDirective;

            while (true)
            {
                var response = (SearchResponse)ldapConnection.SendRequest(this);

                // should only be one
                if (response == null || response.Entries.Count != 1)
                {
                    break;
                }

                var entry = response.Entries[0];

                var growRangeBy = 0;
                if (entry.Attributes.AttributeNames != null)
                {
                    foreach (string attributeName in entry.Attributes.AttributeNames)
                    {
                        currentExpansionDirective = attributeName;
                        isLastSearch = currentExpansionDirective.IndexOf("*", 0, StringComparison.Ordinal) > 0;
                        growRangeBy = entry.Attributes[currentExpansionDirective].Count;
                    }
                }

                foreach (string member in entry.Attributes[currentExpansionDirective].GetValues(typeof(string)))
                {
                    attributeValues.Add(member);
                    rangeStart++;
                }

                if (isLastSearch)
                {
                    break;
                }

                currentExpansionDirective = string.Format(rangeExpansionDirectiveTemplate, rangeStart, rangeStart + growRangeBy);
                Attributes.Clear();
                Attributes.Add(currentExpansionDirective);
            }

            return attributeValues;
        }
    }
}
